#include "socket.h"
#include <arpa/inet.h>
#include <string.h>
#include <stdlib.h>

int initSocket()
{
    int fd = socket(AF_INET,SOCK_STREAM,0);
    if(fd == -1)
    {
        perror("socket");
        return -1;
    }
    return fd; 
}


void initSockaddr(struct sockaddr* addr,unsigned short port,const char* ip)
{
    struct sockaddr_in* addr_in = (struct sockaddr_in*)(addr);
    addr_in->sin_port = htons(port);
    addr_in->sin_family = AF_INET;
    addr_in->sin_addr.s_addr = inet_addr(ip);
}

int setListen(int fd,unsigned short port)
{
    struct sockaddr addr;
    initSockaddr(&addr,port,"0.0.0.0");//INADDR_ANY
    //设置端口复用
    int opt = 1;
    setsockopt(fd,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt));
    //将套接字与（ip + port）进行绑定
    int ret = bind(fd,&addr,sizeof(addr));
    if(ret == -1)
    {
        perror("bind");
        return -1;
    }
    ret = listen(fd,backlog);
    if(ret == -1)
    {
        perror("listen");
        return -1;
    }
    return 0;
}

int acceptConnect(int fd,struct sockaddr* addr)
{
    int connfd;
    if(addr == NULL)
    {
        connfd = accept(fd,NULL,NULL);
    }
    else
    {
        socklen_t len = sizeof(struct sockaddr);
        connfd = accept(fd,addr,&len);
    }
    if(connfd == -1)
    {
        perror("accept");
        return -1;
    }
    return connfd;
}

int connectToHost(int fd,unsigned short port,const char* ip)
{
    struct sockaddr addr;
    initSockaddr(&addr,port,ip);
    int ret = connect(fd,&addr,sizeof(addr));
    if(ret == -1)
    {
        perror("connect");
        return -1;
    }
}

int readn(int fd,char* buffer,int size)
{
    int left = size;
    char* ptr = buffer;
    int readBytes = 0;
    while(left)
    {
        readBytes = read(fd,ptr,left);
        if(readBytes == -1)
        {
            if(errno == EINTR)//被信号中断
            {
                readBytes = 0;
            }
            else
            {
                perror("read");
                return -1;
            }
        }
        else if(readBytes == 0)
        {
            printf("对端主动断开连接\n");
            return -1;
        }
        ptr += readBytes;
        left -= readBytes;
    }
    return size;
}

int writen(int fd,const char* buffer,int size)
{
    int left = size;
    const char* ptr = buffer;
    int writeBytes = 0;
    while(left)
    {
        writeBytes = write(fd,ptr,left);
        if(writeBytes <= 0)
        {
            if(errno == EINTR)//被信号中断
            {
                writeBytes = 0;
            }
            else
            {
                perror("write");
                return -1;
            }
        }
        left -= writeBytes;
        ptr += writeBytes;
    }
    return size;
}

bool sendMessage(int fd,const char* buffer,int length,enum Type t)
{
    // printf("buffer : %s\n",buffer);
    // printf("len : %d\n",length);
    int dataLen = length + 1 + sizeof(int);
    char* data = (char*)malloc(dataLen);
    if(data == NULL)
    {
        perror("malloc");
        return false;
    }
    int netLen = htonl(length + 1);
    memcpy(data,&netLen,sizeof(int));
    char* ch =  t == Heart ?  "H" : "M";
    memcpy(data + sizeof(int),ch,sizeof(char));
    memcpy(data + sizeof(int) + 1,buffer,length);
    int ret = writen(fd,data,dataLen);
    free(data);
    return ret == dataLen;
}

int recvMessage(int fd,char** buffer,enum Type* t)
{
    int dataLen = 0;
    int ret = readn(fd,(char*)&dataLen,sizeof(int));
    if(ret == -1)
    {
        *buffer = NULL;
        return -1;
    }
    dataLen = ntohl(dataLen);
    char ch;
    readn(fd,&ch,1);
    *t = ch == 'H' ? Heart : Message;
    char* tmpbuffer = (char*)calloc(dataLen,sizeof(char));//多开一个字节存储\0
    if(tmpbuffer == NULL)
    {
        *buffer = NULL;
        return -1;
    }
    ret = readn(fd,tmpbuffer,dataLen - 1);
    if(ret != dataLen - 1)
    {
        free(tmpbuffer);
        *buffer = NULL;
        return -1;
    }
    *buffer = tmpbuffer;
    return ret;
}